package com.myclass.dynamicdatasource.configuration;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * Desc: 通过aop的方式来拦截所有的mappper接口方法，
 *       1。根据其方法所有的包路径来判断走那个类型的数据库
 *       2。再根据其方法名来定位该类型库下使用主库还是从库
 *
 * @author wujw
 * @email jiwenwu@outlook.com
 * @date 2018-12-12
 */
@Aspect
@Component
public class DynamicDataSourceAspect {

    private static final String TYPE_ONE_PACKAGE = "com.myclass.dynamicdatasource.mapper.typeone";
    private static final String TYPE_TWO_PACKAGE = "com.myclass.dynamicdatasource.mapper.typetwo";

    private final String[] QUERY_PREFIX = {"select","list","get","query","find"};

    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);

    /**
     * 拦截mapper包下及其子包下所有的方法
     */
    @Pointcut("execution( * com.myclass.dynamicdatasource.mapper..*(..))")
    public void daoAspect() {
    }

    @Before("daoAspect()")
    public void switctDataSource(JoinPoint joinPoint) {
        String interfaceName  = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();

        boolean isQuery = false;
        // 先根据方法名匹配原则来判断是读还是写
        for (String prefix : QUERY_PREFIX) {
            if (methodName.toLowerCase().startsWith(prefix)){
                isQuery = true;
                break;
            }
        }

        // 根据报名来确定用走哪个库的主库或从库
        if (interfaceName.contains(TYPE_ONE_PACKAGE)) {
            // type-one 查询走从库
            if (isQuery) {
                DynamicDataSourceContextHolder.useTypeOneSlaveDataSource();
                logger.info("方法【 {} 】切换数据源为  >>>>>>> [ {} ] ", joinPoint.getSignature(), DynamicDataSourceContextHolder.getDataSourceKey());
            } else {
               DynamicDataSourceContextHolder.useTypeOneMasterDataSource();
                logger.info("方法【 {} 】切换数据源为  >>>>>>> [ {} ] ", joinPoint.getSignature(), DynamicDataSourceContextHolder.getDataSourceKey());
            }
        }

        if (interfaceName.contains(TYPE_TWO_PACKAGE)) {
            // type-two 查询走从库
            if (isQuery) {
                DynamicDataSourceContextHolder.useTypeTwoSlaveDataSource();
                logger.info("方法【 {} 】切换数据源为  >>>>>>> [ {} ] ", joinPoint.getSignature(), DynamicDataSourceContextHolder.getDataSourceKey());
            } else {
                DynamicDataSourceContextHolder.useTypeTwoMasterDataSource();
                logger.info("方法【 {} 】切换数据源为  >>>>>>> [ {} ] ", joinPoint.getSignature(), DynamicDataSourceContextHolder.getDataSourceKey());
            }
        }
    }

    @After("daoAspect()")
    public void restoreDataSource(){
        DynamicDataSourceContextHolder.clearDataSourceKey();
    }

}
